import numpy as np

# 相似度计算

def CalSimEuD(dataA, dataB):
    '''【目的】计算欧氏距离（对应值的差平方之和再开方），注重数据之间的绝对位置而不是方向
       【输入】np.array
       【输出】已进行归一化，取值(0,1]，数值越大表示相似性越高，数值为1代表完全相似'''
    # np.linalg.norm用于范数计算，默认二范数，相当于平方和开根号
    # 原始取值为(0,正无穷),归一化到(0,1]区间：1/(1+原始值）
    return 1 / (1 + np.linalg.norm(dataA - dataB))


def CalSimCosine(dataA, dataB):
    '''【目的】计算余弦相似度，注重数据的方向而非绝对位置
       【输入】np.array
       【输出】已进行归一化，取值[0,1]，数值越大表示相似性越高，数值为1代表完全相似'''
    sumData = np.dot(dataA, dataB)  # 公式中的分子，向量的内积
    # np.linalg.norm用于范数计算，默认二范数，相当于平方和开根号
    denom = np.linalg.norm(dataA) * np.linalg.norm(dataB)  # 公式中的分母
    # 原始取值为[-1,1]，归一化到[0,1]区间：0.5 + 0.5 * 原始值
    return 0.5 + 0.5 * (sumData / denom)


def CalSimPearson(dataA, dataB):
    '''【目的】计算皮尔逊相关系数，是对余弦相似度的修正，分子和分母都需要减去输入数据集各自本身向量的均值，以达到中心化
       【输入】np.array，不可以输入常量数组如[1,1]
       【输出】已进行归一化，取值[0,1]，数值越大表示相似性越高，数值为1代表完全相似'''
    # np直接计算出的皮尔逊相关系数取值范围[-1,1]，归一化到[0,1]区间：0.5 + 0.5 * 原始值
    return 0.5 + 0.5 * np.corrcoef(dataA, dataB, rowvar=0)[0][1]


def CalSimJaccard(dataA, dataB):
    '''【目的】计算Jaccard相似度，度量集合之间的差异，共有的元素越多则越相似
       【输入】np.array
       【输出】取值[0,1]，数值越大表示相似性越高，数值为1代表完全相似'''
    A_len, B_len = len(dataA), len(dataB)
    C = [i for i in dataA if i in dataB]  # 取交集
    C_len = len(C)  # 交集含有元素的个数
    return C_len / (A_len + B_len - C_len)



if __name__ == '__main__':

    # jc = "3.40	3.65	1.78".split("	")  # 竞猜
    # op = "3.68	3.74	1.86".split("	")  # 欧赔
    # my_list = [[float(a) for a in jc]]
    # cd = [float(a) for a in op]

    x1 = np.array([2.44,4.28,4.01,5.9])
    x2 = np.array([2.44,4.01,4.28,5.9])

    print('完全相同的情况下，三个相似度结果都是1代表完全相似')
    print('欧氏距离：', CalSimEuD(x1, x2))
    print('余弦相似度：', CalSimCosine(x1, x2))
    print('皮尔逊（归一化版）：', CalSimPearson(x1, x2))
    print('Jaccard相似度：', CalSimJaccard(x1, x2))
    # x2 = np.array(cd)

    # res = [round(CalSimEuD(np.array(ds),x2),4) for ds in my_list]
    # print(res)
